<template>
  <div class="_flex_column_ _flex_110_" style="margin: 16px 16px 0 16px ;border: 2px solid #F0F0F0;">

    <!--表格选项-->
    <div class="_flex_space_between_"
         style="height:50px;width:100%;padding: 0 16px ;background: #FFFFFF;border-bottom: 1px solid #F0F0F0; align-items: center">

      <div style="color: rgba(0,0,0,.85);font-size: 16px;font-weight: 700">路径（Path，按顺序取鼠标左键点击位置）
      </div>

      <div style="flex: 1 1 0"></div>


      <div
          style="font-size: 12px;color: #a8a3a3">结束绘制(鼠标右键)
      </div>

      <a-divider type="vertical"/>

      <div
          style="font-size: 12px;color: #a8a3a3">移动画布(ctrl+鼠标左键)
      </div>

      <a-divider type="vertical"/>

      <div>
       <span
           style="font-size: 14px;color: #000000;margin-right: 3px">自由绘制</span>
        <a-switch v-model:checked="freeDraw" checked-children="开启" un-checked-children="关闭"/>
      </div>

      <a-divider type="vertical"/>

      <a-button type="primary" size="small" ghost @click="clearCanvas">清屏</a-button>

      <!--          <a-divider type="vertical"/>-->
      <!--          <a-button type="primary" size="small" ghost @click="openAdd_">绘制</a-button>-->
    </div>

    <div class="_flex_110_" ref="canvasSize" style="background: #F0F0F0;border: 1px dashed #000000;">
      <canvas id="canvas"/>
    </div>
  </div>
</template>

<script setup>
import {onMounted, ref, watch} from 'vue'
import $store from "@/common/store/_store";
import {message} from "ant-design-vue";

//键盘按下状态
let keydown = {
  control: false
}

window.addEventListener("keydown", function (e) {
  if (e.key == 'Control') {
    keydown.control = true
  }
  if (e.key == 'F9') {
    freeDraw.value = true
  }
}, false);

window.addEventListener("keyup", function (e) {
  //console.log("keyup")
  if (e.key == 'Control') {
    keydown.control = false
  }
}, false);

// 鼠标按下时指针
let downPointer = null
// 鼠标抬起时指针
let upPointer = null
// 鼠标当前指针
let currentPointer = null

// 当前操作对象
let currentGraph = null

//开启自由绘制
let freeDraw = ref(true)
let canvasSize = ref(null)
let canvas = null
let canvasConfig = {
  //鼠标当前状态
  mouseIsDown: false,
  //还原缩放大小
  defaultZoom: 1,
  //区域选择：允许选择
  selection: true,
  //区域选择：背景填充 ; 背景透明'transparent'
  selectionColor: 'transparent',
  //区域选择：边框颜色
  selectionBorderColor: 'transparent',
  //对象选中：false=允许；true=禁止
  skipTargetFind: true,
  //开启鼠标右键（左中右，123）
  fireRightClick: true,
  //关闭默认右键菜单
  stopContextMenu: true
}

//监控菜单关闭
watch(() => freeDraw.value, (item) => {
  //已开启
  if (item) {
    message.success("自由绘制已开启", 1)
    canvas.skipTargetFind = true
    canvas.selection = true
    canvas.selectionColor = 'transparent'
    canvas.selectionBorderColor = 'transparent'

  }
  if (!item) {
    message.success("绘制完成,按【F9】开启自由绘制", 1)
    canvas.skipTargetFind = false
    canvas.selection = true
    canvas.selectionColor = 'rgba(24,22,22,0.1)'
    canvas.selectionBorderColor = 'rgba(24,22,22,0.3)'
  }
})

onMounted(() => {
  canvas = new fabric.Canvas('canvas')
  canvas.selection = canvasConfig.selection
  canvas.selectionColor = canvasConfig.selectionColor
  canvas.selectionBorderColor = canvasConfig.selectionBorderColor
  canvas.skipTargetFind = canvasConfig.skipTargetFind
  canvas.fireRightClick = canvasConfig.fireRightClick
  canvas.stopContextMenu = canvasConfig.stopContextMenu
  canvas.preserveObjectStacking = true

  //鼠标事件：按下
  canvas.on('mouse:down', canvasMouseDown)
  //鼠标事件：抬起
  canvas.on('mouse:up', canvasMouseUp)
  //鼠标事件：移动
  canvas.on('mouse:move', canvasMouseMove)
  //鼠标事件：滚轮
  canvas.on('mouse:wheel', canvasMouseWheel)

  //监控窗口大小变更
  window.onresize = () => {
    resizeCanvas()
  }

  //监控菜单关闭
  watch(() => $store.state.closeLeftSider, () => {
    setTimeout(() => {
      resizeCanvas()
    }, 300)
  })
  resizeCanvas()
})

//canvas:绘制图形
function draw(event) {
  //初始化
  if (currentGraph == null) {
    currentGraph = new fabric.Polyline(
        [
          {x: downPointer.x, y: downPointer.y},
          {x: downPointer.x, y: downPointer.y},
        ],
        {
          fill: 'transparent',
          stroke: 'rgba(189,59,90,0.77)', // 边框颜色：骚粉
          strokeWidth: 5, // 边框粗细：5px
          strokeDashArray: [5, 7, 10], // 边框虚线规则：填充5px 空5px ;填充7px 空10px
          objectCaching: false
        }
    )
    canvas.add(currentGraph)
  }

  //追加：下一条线
  if (currentGraph != null) {
    currentGraph.points.push({
      x: currentPointer.x,
      y: currentPointer.y
    })
    canvas.renderAll()
  }
}

//canvas:更新图形
function update(event) {
  //更新最后一个坐标
  if (currentGraph) {
    let points = currentGraph.points
    points[points.length - 1].x = currentPointer.x
    points[points.length - 1].y = currentPointer.y
    canvas.renderAll()
  }
}

//canvas:绘制结束，替换图形
function drawReplace(event) {
  //console.log(currentGraph.points)

  if (currentGraph && currentGraph.points.length > 3) {
    //全部坐标
    let points = currentGraph.points
    //去掉第一个坐标
    points.splice(0, 1)
    //去掉最后一个坐标
    points.splice(points.length - 1, 1)
    //删除当前图形
    canvas.remove(currentGraph)

    //路径
    let M_X = points[0].x
    let M_Y = points[0].y
    let pathStr = `M ${M_X} ${M_Y}`
    for (let i = 1; i < points.length; i++) {
      let L_X = points[i].x
      let L_Y = points[i].y
      pathStr += `L ${L_X} ${L_Y}`
    }
    pathStr += ' z'

    //图形
    let replaceGraph = new fabric.Path(pathStr, {
      fill: 'transparent',
      stroke: 'rgba(0, 0, 0.0.5)',
      strokeWidth: 3, // 边框粗细：3px
      objectCaching: false
    })
    canvas.add(replaceGraph)
    canvas.renderAll()

    freeDraw.value = false;
    currentGraph = null
  }

  //坐标不足，绘制失败
  else {
    //删除当前图形
    canvas.remove(currentGraph)
    freeDraw.value = false
    currentGraph = null
  }

}

//鼠标事件：按下
function canvasMouseDown(event) {
  canvasConfig.mouseIsDown = true
  downPointer = event.absolutePointer

  //鼠标左键
  if (event.button === 1) {
    //自由绘制
    if (freeDraw.value) {
      draw(event)
    }
  }

  // 鼠标右键：绘制完成，
  if (event.button === 3) {
    drawReplace(event)
  }

}

//鼠标事件：抬起
function canvasMouseUp(event) {
  canvasConfig.mouseIsDown = false
  upPointer = event.absolutePointer
}

//鼠标事件：移动
function canvasMouseMove(event) {
  currentPointer = event.absolutePointer

  //自由绘制已开启
  if (freeDraw.value) {
    update(event)
    return;
  }

  if (canvasConfig.mouseIsDown && !freeDraw.value && keydown.control) {
    let delta = new fabric.Point(event.e.movementX, event.e.movementY)
    canvas.relativePan(delta)
  }
}

//鼠标事件：滚轮
function canvasMouseWheel(event) {
  // 滚轮向上滚一下是 -100，向下滚一下是 100
  let delta = event.e.deltaY
  // 获取画布当前缩放值
  let zoom = canvas.getZoom()

  zoom -= 0.005 * delta
  if (zoom > 20) zoom = 20
  if (zoom < 1) zoom = 1
  // 设置画布缩放比例
  canvas.zoomToPoint(
      {
        x: event.e.offsetX,
        y: event.e.offsetY
      },
      zoom
  )
}

//canvas：自适应缩放
function resizeCanvas() {

  canvas.setWidth(0)
  canvas.setHeight(0)
  //
  canvas.setWidth(canvasSize.value.offsetWidth)
  canvas.setHeight(canvasSize.value.offsetHeight)

  // 计算
  const [minX, minY, maxX, maxY] = calcBorder()

  // 平移
  const panX = (maxX - minX - canvas.width) / 2 + minX
  const panY = (maxY - minY - canvas.height) / 2 + minY
  canvas.absolutePan({x: panX, y: panY})

  //缩放
  let zoom = Math.min(canvas.width / (maxX - minX), canvas.height / (maxY - minY))

  //计算缩放中心
  let zoomPoint = new fabric.Point(canvas.width / 2, canvas.height / 2)

  //开始缩放
  canvas.zoomToPoint(zoomPoint, zoom)

  canvasConfig.defaultZoom = zoom

  //console.log("canvas:width", canvas.width)
  //console.log("canvas:height", canvas.height)
}

//canvas：画布边界 [minX, minY, maxX, maxY]
function calcBorder() {

  //先还原缩放比例与位置
  canvas.setZoom(1)
  canvas.absolutePan({x: 0, y: 0})

  //遍历所有对对象，获取最小坐标，最大坐标
  let [minX, minY, maxX, maxY] = [0, 0, canvas.width, canvas.height]
  let objects = canvas.getObjects()
  if (objects.length > 0) {
    let rect = objects[0].getBoundingRect()
    minX = rect.left
    minY = rect.top
    maxX = rect.left + rect.width
    maxY = rect.top + rect.height
    for (let i = 1; i < objects.length; i++) {
      rect = objects[i].getBoundingRect()
      minX = Math.min(minX, rect.left)
      minY = Math.min(minY, rect.top)
      maxX = Math.max(maxX, rect.left + rect.width)
      maxY = Math.max(maxY, rect.top + rect.height)
    }
  }
  return [minX, minY, maxX, maxY]
}

//canvas：缩放
function setZoom(zoomNum) {
  let zoom = zoomNum + (zoomNum === 0 ? 1 : canvas.getZoom())
  zoom = Math.max(canvasConfig.defaultZoom, zoom) // 最小为原来
  zoom = Math.min(3, zoom) // 最大是原来的3倍
  const zoomPoint = new fabric.Point(0, 0)
  canvas.zoomToPoint(zoomPoint, zoom)
}

//canvas:清屏
function clearCanvas() {
  canvas.clear()
  canvas.renderAll()
  resizeCanvas()
}

</script>

<style lang="less">
</style>

<style scoped lang="less">

</style>
